package cz.acies.genea.ui.chart;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;


import cz.acies.data.DBConnector;
import cz.acies.data.persist.ModelObject;
import cz.acies.genea.data.dao.GedFamilyDAO;
import cz.acies.genea.data.dao.GedPersonDAO;
import cz.acies.genea.data.persist.GedFamily;
import cz.acies.genea.data.persist.GedPerson;
import cz.acies.genea.data.persist.GedPersonBinding;
import cz.acies.genea.data.persist.GedProject;
import cz.acies.uniql.sql.element.UniQLCondition;
import cz.acies.uniql.sql.element.UniQLWhere;
import cz.acies.utils.UIDGenerator;

public class TreeChartModel
{
	public static void main(String[] args) {
		try {
			/*
			// HOME
			String jdbcUrl = "jdbc:mysql://localhost:3306/gedcom";
			String jdbcDriver = "org.gjt.mm.mysql.Driver";
			
			Properties props = new Properties();
			props.setProperty("user", "root");
			props.setProperty("password", "smart");
			props.setProperty("useUnicode", "true");
			props.setProperty("characterEncoding", "UTF8");
			props.setProperty("characterSetResults", "UTF8");
			*/
			// WORK
			String jdbcUrl = "jdbc:mysql://localhost:3305/gedcom";
			String jdbcDriver = "org.gjt.mm.mysql.Driver";
			
			Properties props = new Properties();
			props.setProperty("user", "root");
			props.setProperty("password", "");
			props.setProperty("useUnicode", "true");
			props.setProperty("characterEncoding", "UTF8");
			props.setProperty("characterSetResults", "UTF8");
			
			String dialectClass = "cz.acies.uniql.dialect.MySQLDialect"; 
			
			DBConnector connector = DBConnector.instance();
			connector.setUrl(jdbcUrl);
			connector.setDriver(jdbcDriver);
			connector.setDialectClass(dialectClass);
			connector.setProps(props);
			connector.initialize();
			
			// HOME
			//"GE.R.9ZGDO4RZJU6WVKM";
			//GedFamily root = new GedFamilyDAO().selectById("GE.F.0T373E3GDJ03004"); // J+J
			//GedFamily root = new GedFamilyDAO().selectById("GE.F.DG6BV9NJJXLESKN");	// J+M
			// WORK
			GedFamily root = new GedFamilyDAO().selectById("GE.F.KUGK7AAMBXTQFBI");
			GedPerson selected = root.getMan();
			//GedPerson selected = root.getWoman();
			
			TreeChartModel inst = new TreeChartModel();
			inst.setRoot(root);
			inst.setSelected(selected);
			inst.build();
			//String treeData = new Gson().toJson(inst.toJson()); 
			
		} catch (Exception exc) {
			exc.printStackTrace();
		}
	}
	
	protected GedProject project = null;
	protected GedFamily root = null;
	protected GedPerson selected = null;
	
	protected Map<Integer, TreeChartRow> rows = new TreeMap<Integer, TreeChartRow>();
	protected Map<String, TreeChartNode> cells = new LinkedHashMap<String, TreeChartNode>();
	protected Map<String, TreeChartCard> cards = new LinkedHashMap<String, TreeChartCard>();
	
	protected TreeChartNode parentsTree = null;
	protected TreeChartNode childrenTree = null;
	
	protected GedFamilyDAO fDao;
	protected GedPersonDAO pDao;

	protected int minRow = 0;
	protected int maxRow = 0;
	
	public TreeChartModel() {
		fDao = new GedFamilyDAO();
		pDao = new GedPersonDAO();
	}

	
	public void build() {
		try {
			rows.clear();
			String projectId = "GE.P.000000000000001"; 
			if (this.project == null) {
				this.project = new GedProject(projectId, new LinkedHashMap<String, Object>());
			}
			List<GedPerson> people = pDao.selectByProjectId(projectId); 
			for (ModelObject obj : people) {
				if (obj instanceof GedPerson) {
					GedPerson person = (GedPerson) obj;
					//person = this.expletoPerson(person); 
					project.addPerson(person);
				}
			}
			List<GedFamily> families = fDao.selectByProjectId(projectId);
			for (ModelObject obj : families) {
				if (obj instanceof GedFamily) {
					GedFamily family = (GedFamily) obj;
					if (family.hasMan() && family.getMan().hasId()) {
						String id = family.getMan().getId();
						if (project.getPeople().containsKey(id)) {
							GedPerson person = project.getPeople().get(id); 
							family.setMan(person);
							person.addPartner(family);
						}
					}
					if (family.hasWoman() && family.getWoman().hasId()) {
						String id = family.getWoman().getId();
						if (project.getPeople().containsKey(id)) {
							GedPerson person = project.getPeople().get(id); 
							family.setWoman(person);
							person.addPartner(family);
						}
					}
					UniQLWhere where = new UniQLWhere()
					.add(new UniQLCondition("person_bindings.objectId", "=", "'"+family.getId()+"'"), "AND")
					.add(new UniQLCondition("person_bindings.bindingType", "=", "'CHILD'"), "AND")
					.add(new UniQLCondition("person_bindings.extend", "=", "'FAMILY'"));
					
					List<ModelObject> binds = fDao.selectByWhere("person_bindings", where, GedPersonBinding.class);
					for (ModelObject object : binds) {
						if (object instanceof GedPersonBinding) {
							GedPersonBinding bind = (GedPersonBinding) object;
							String id = bind.getConnectId();
							if (project.getPeople().containsKey(id)) {
								GedPerson person = project.getPeople().get(id);
								family.addChild(person);
							}
						}
					}
					project.addFamily(family);
				}
			}
			root = project.getFamilies().get(root.getId());
			selected = project.getPeople().get(selected.getId());
			parentsTree = buildParentsTree(null, root);
			childrenTree = buildChildrenTree(null, root);
			minRow = Collections.max(rows.keySet());
			maxRow = Collections.min(rows.keySet());
		} catch (Exception exc) {
			exc.printStackTrace();
		}
	}

	public List<Map<String, Object>> toJson() {
		List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();;
		try {
			data.add(parentsTree.toJson());
			data.add(childrenTree.toJson());
		} catch (Exception exc) {
			exc.printStackTrace();
		}
		return data;
	}
	
	public TreeChartNode buildParentsTree(TreeChartNode parent, GedFamily family) {
		TreeChartNode node = new TreeChartNode(family).setModel(this); 
		try {
			if (parent == null) {
				node.setLevel(0);
			} else {
				int row = parent.getLevel();
				node.setLevel(row+1);
			}
			if (family.hasMan() && family.getMan().hasParents()) {
				GedFamily parents = family.getMan().getParents();
				if (parents.hasId() && project.getFamilies().containsKey(parents.getId())) {
					parents = project.getFamilies().get(parents.getId());
					node.addChild(buildParentsTree(node, parents));
				} else {
					
				}
			}
			if (family.hasWoman() && family.getWoman().hasParents()) {
				GedFamily parents = family.getWoman().getParents();
				if (parents.hasId() && project.getFamilies().containsKey(parents.getId())) {
					parents = project.getFamilies().get(parents.getId());
					node.addChild(buildParentsTree(node, parents));
				} else {
					
				}
			}
			int level = node.getLevel() * -1;
			TreeChartRow map = rows.get(level);
			//if (map == null)  map = new LinkedHashMap<String, TreeChartNode>();
			if (map == null)  map = new TreeChartRow(level);
			map.put(node.getId(), node); 
			rows.put(level, map);
			cells.put(node.getId(), node);
		} catch (Exception exc) {
			exc.printStackTrace();
		}
		return node;
	}
	
	public TreeChartNode buildChildrenTree(TreeChartNode parent, GedFamily family) {
		TreeChartNode node = new TreeChartNode(family).setModel(this);
		try {
			if (parent == null) {
				node.setLevel(0);
			} else {
				int row = parent.getLevel();
				node.setLevel(row+1);
				node.setParent(parent);
			}
			int level = node.getLevel();
			TreeChartRow map = rows.get(level);
			if (map == null)  map = new TreeChartRow(level);
			map.put(node.getId(), node); 
			rows.put(level, map);
			cells.put(node.getId(), node);
			
			if (!family.getChildren().isEmpty()) {
				for (Map.Entry<String, GedPerson> e : family.getChildren().entrySet()) {
					String id = e.getKey();
					GedPerson person = e.getValue();
					List<GedFamily> partners = pDao.selectPartnersFamily(person);
					if (partners.isEmpty()) {
						GedFamily f = new GedFamily();
						f.setId(UIDGenerator.createUID("GE.F"));
						if (person.getGender().equals("M")) {
							f.setMan(person);
						} else {
							f.setWoman(person);
						}
						TreeChartNode child = buildChildrenTree(node, f);
						TreeChartCard c1 = child.createLeftCard(f.getMan());
						if (c1.hasPerson()) cards.put(c1.getPerson().getId(), c1);
						TreeChartCard c2 = child.createRightCard(f.getWoman());
						if (c2.hasPerson()) cards.put(c2.getPerson().getId(), c2);
						node.addChild(child/*new TreeChartNode(f)*/);
						/*
						level = child.getLevel();
						Map<String, TreeChartNode> map = rows.get(level);
						if (map == null)  map = new TreeChartRow(level);
						map.put(child.getId(), child); 
						rows.put(level, map);
						cells.put(child.getId(), child);
						*/
					} else {
						person.setPartners(partners);
						for (GedFamily f : partners) {
							if (project.getFamilies().containsKey(f.getId())) { 
								f = project.getFamilies().get(f.getId());
							}
							TreeChartNode child = buildChildrenTree(node, f);
							TreeChartCard c1 = child.createLeftCard(f.getMan());
							if (c1.hasPerson()) cards.put(c1.getPerson().getId(), c1);
							TreeChartCard c2 = child.createRightCard(f.getWoman());
							if (c2.hasPerson()) cards.put(c2.getPerson().getId(), c2);
							node.addChild(child);
							/*
							level = child.getLevel();
							Map<String, TreeChartNode> map = rows.get(level);
							if (map == null)  map = new TreeChartRow(level);
							map.put(child.getId(), child); 
							rows.put(level, map);
							cells.put(child.getId(), child);
							*/
						}
					}
				}
			} else {
				/*
				TreeChartNode child = new TreeChartNode(new GedFamily(UIDGenerator.createUID("GE.F")));
				TreeChartCard c1 = child.createLeftCard(child.getFamily().getMan());
				//if (c1.hasPerson()) cards.put(c1.getPerson().getId(), c1);
				TreeChartCard c2 = child.createRightCard(child.getFamily().getWoman());
				//if (c2.hasPerson()) cards.put(c2.getPerson().getId(), c2);
				
				int row = node.getLevel(); 
				child.setLevel(row+1);
				child.setParent(node);

				level = child.getLevel();
				map = rows.get(level);
				if (map == null)  map = new TreeChartRow(level);
				map.put(child.getId(), child); 
				rows.put(level, map);
				cells.put(child.getId(), child);

				node.addChild(child);
				*/
			}
		} catch (Exception exc) {
			exc.printStackTrace();
		}
		return node;
	}
	/*
	private Predicate bindTpeCond(final String ord) {
		return new Predicate() {
			public boolean evaluate(Object o) {
				return (o instanceof GedPersonBinding) ? ((GedPersonBinding) o).getBindingType().equals(""+ord) : true;
			}
		};
	}

	private Predicate bindExtCond(final String ord) {
		return new Predicate() {
			public boolean evaluate(Object o) {
				return (o instanceof GedPersonBinding) ? ((GedPersonBinding) o).getExtend().equals(""+ord) : true;
			}
		};
	}
	*/
	// -----  -----------------------------------------------------------------
	
	public Map<Integer, TreeChartRow> getRows() {
		return rows;
	}

	public void setRows(Map<Integer, TreeChartRow> rows) {
		this.rows = rows;
	}

	
	public Map<String, TreeChartNode> getCells() {
		return cells;
	}


	public void setCells(Map<String, TreeChartNode> cells) {
		this.cells = cells;
	}


	public Map<String, TreeChartCard> getCards() {
		return cards;
	}


	public void setCards(Map<String, TreeChartCard> cards) {
		this.cards = cards;
	}
	
	// -----  -----------------------------------------------------------------

	public TreeChartNode getParentsTree() {
		return parentsTree;
	}


	public void setParentsTree(TreeChartNode parentsTree) {
		this.parentsTree = parentsTree;
	}


	public TreeChartNode getChildrenTree() {
		return childrenTree;
	}


	public void setChildrenTree(TreeChartNode childrenTree) {
		this.childrenTree = childrenTree;
	}

	// -----  -----------------------------------------------------------------
	
	public GedProject getProject() {
		return project;
	}
	
	public void setProject(GedProject project) {
		this.project = project;
	}
	
	public GedFamily getRoot() {
		return root;
	}
	
	public void setRoot(GedFamily family) {
		this.root = family;
	}
	
	public GedPerson getSelected() {
		return selected;
	}
	
	public void setSelected(GedPerson seleted) {
		this.selected = seleted;
	}


	public int getMinRow() {
		return minRow;
	}


	public void setMinRow(int minRow) {
		this.minRow = minRow;
	}


	public int getMaxRow() {
		return maxRow;
	}


	public void setMaxRow(int maxRow) {
		this.maxRow = maxRow;
	}
}
